# -*- coding: utf-8 -*-
"""
cre_examples.py -- List of examples
"""

EXAMPLES = [

    # TODO: How to write a sequence of choices:
    # (either 'a' or 'b') (either 'c' or 'd')
    # -> (a|b)(c|d)
    #
    # Choice of sequences
    # either (digit '%') or (wordchar '!')
    # -> \d%|\w!
    #
    # Choice of choices:

    # either (either 'a' or 'b') or (either 'c' or 'd')
    # -> (a|b)|(c|d)

{ 'name': 'dollars',
  'cre': """\
'$' digit+ '.' digit^2
""",
  'match': [
    '$2.00',
    '$100.89'
    ],
  'nomatch': [
    ],
  },

{ 'name': 'ip',
  'cre': """\
D     = digit^(1..3)
Start = D '.' D '.' D '.' D
""",
  'match': [
    '192.168.0.1',
    '0.0.0.0',
    'ip: 192.168.0.123 ...',  # trailing OK ?
    #'192.168.0.123456',  # trailing OK ?
    ],
  'nomatch': [
    '0.0.0.a',
    '192.168.012345.1',
    ],
  },

{ 'name': 'number',
  'cre': """\
Sign  = chars[&hyphen +]
Start = { Sign? }
        { either digit+ ('.' digit*)? or '.' digit+ }
        ( chars[e E] { Sign? } { digit+ } )?
""",
  'capture': [
    ('1', {1: '', 2: '1', 3: None, 4: None, 'MATCH': '1'}),
    ('-1.0', {1: '-', 2: '1.0', 3: None, 4: None, 'MATCH': '-1.0'}),
    '.1',
    '0.1',
    '1e6',
    '5.0E9',
    '-50e-9',
    '1.1.1',  # trailing
    ],
  'nomatch': [
    ],
  },

{ 'name': 'pass',
  'cre': """\
%ASSERT( any* digit )               # must contain a digit
%ASSERT( any* chars[a-z] )          # must contain a lower case letter
%ASSERT( any* chars[A-Z] )          # must contain an upper case letter
%ASSERT( any* chars[@ &hash $ %] )  # must contain one of these symbol
any^(6..20)                         # 6 to 20 chars
""",
  'match': [
    'abCD90@',
    ],
  'nomatch': [
    'ab',
    'CD',
    '90',
    '@',
    ],
  },
{ 'name': 'hex',
  'cre': """\
H     = chars[A-F a-f 0-9]
Start = '#' either H^3 or H^6
""",
  'match': [
    '#001122',
    '#abc',
    ],
  'nomatch': [
    '#a',
    '#ggg',
    ],
  },


# brainstorm
# DQ    = '"' capture( !chars[ " ]* ) '"'           # double quoted
# SQ    = "'" capture( !chars[ ' ]* ) "'"           # single quoted
{
  'name': 'href',
  'cre': """\
flags(ignorecase)

_     = whitespace*    # optional whitespace
__    = whitespace+    # mandatory whitespace

# double quote, capture non-double quote chars with {}, double quote
DQ    = '"' { !chars["]* } '"'
SQ    = "'" { !chars[']* } "'"           # same for single quotes
NQ    = { !chars[ ' " whitespace > ]+ }  # no quotes, capture the whole thing

# The top level pattern -- now it should be self-explanatory.
Start = '<' _ 'a' __ 'href' _ '=' _ (either DQ or SQ or NQ) _ '>'
""",
  'match': [
    '<a href="http://example.com/">',
    "< a href = ' http://example.com/ ' >",
    '<a href=http://example.com/ >',
    ],
  'nomatch': [
    '<ahref="http://example.com/">',
    ],
  },

# NOTE: Would it be more natural to write like:
# Balanced0    = ...
# Balanced01   = either Balanced0 or '(' Balanced0  ')'
# Balanced012  = either Balanced0 or '(' Balanced01 ')'

{ 'name': 'url-capture',
  'cre': """\
flags(ignorecase)

Protocol   = 'http' 's'? '://'        # http or https protocol

WWW        = 'www' digit^(..3) '.'    # "www.", "www1.", "www2." ... "www999."

# looks like a domain name followed by a slash, e.g. "foo.cn/"
# TODO: change to use .. for char ranges?
DomainLike = chars[ a-z 0-9 . &hyphen ]+ '.' chars[a-z]^(2..4) '/'

# Balanced text, doesn't have () or <>
Balanced   = !chars[ whitespace () <> ]+

# Up to 1 pair of balanced parens    (foo)
Balanced1  = { '(' Balanced ')' }

# Up to 2 pair of balanced parens    (foo) or ((foo))
Balanced12  = '(' { either Balanced or Balanced1 }* ')'

# None of these characters can end a URL.
EndUrl     = !chars[ whitespace ` &bang
                     ()
                     &lbracket &rbracket
                     {}
                     ;: '" ., <> ?
                     0xab 0xbb
                     &201c &201d
                     &2018 &2019
                   ]

Start      = %boundary
             {
                 ( either Protocol or WWW or DomainLike )
                 ( either Balanced or Balanced12 )+
                 ( either Balanced12 or EndUrl )
             }
""",
  'match': """\
http://foo.com/blah_blah
http://foo.com/blah_blah/
(Something like http://foo.com/blah_blah)
http://foo.com/blah_blah_(wikipedia)
http://foo.com/more_(than)_one_(parens)
(Something like http://foo.com/blah_blah_(wikipedia))
http://foo.com/blah_(wikipedia)#cite-1
http://foo.com/blah_(wikipedia)_blah#cite-1
http://foo.com/unicode_(✪)_in_parens
http://foo.com/(something)?after=parens
http://foo.com/blah_blah.
http://foo.com/blah_blah/.
<http://foo.com/blah_blah>
<http://foo.com/blah_blah/>
http://foo.com/blah_blah,
http://www.extinguishedscholar.com/wpglob/?p=364.
http://✪df.ws/1234
http://➡.ws/䨹
www.c.ws/䨹
<tag>http://example.com</tag>
Just a www.example.com link.
http://example.com/something?with,commas,in,url, but not at end
bit.ly/foo
“is.gd/foo/”
WWW.EXAMPLE.COM
http://www.asianewsphoto.com/(S(neugxif4twuizg551ywh3f55))/Web_ENG/View_DetailPhoto.aspx?PicId=752
http://www.asianewsphoto.com/(S(neugxif4twuizg551ywh3f55))
http://lcweb2.loc.gov/cgi-bin/query/h?pp/horyd:@field(NUMBER+@band(thc+5a46634))
""".splitlines(),
  'nomatch': """\
6:00p
filename.txt
""".splitlines(),
  }
]


# Original regex
ORIG_URL_REGEX = r"""(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))"""


def GetExample(name):
  for e in EXAMPLES:
    if e.get('name') == name:
      return e
  return None


def PrintJson(example_name):
  import json
  import os

  annex_root = os.path.normpath(
      os.path.join(os.path.abspath(sys.argv[0]), '../..'))
  sys.path.append(annex_root)
  import annex

  e = GetExample(example_name)
  cre = e['cre']
  r = annex.Regex(cre)
  py_re = r.to_py()

  cre_html = annex.cre_to_html(cre)

  match = e.get('match', [])
  match_lines = []
  for m in match:
    if isinstance(m, basestring):
      match_lines.append(m)
    elif isinstance(m, tuple):
      match_lines.append(m[0])
    else:
      raise AssertionError("Invalid match %r" % m)

  nomatch = e.get('nomatch', [])
  nomatch_lines = []
  for m in nomatch:
    nomatch_lines.append(m)

  # Syntax highlighted HTML, Python equivalent, and input examples.
  d = {
    'cre_html': cre_html, 'pyre': py_re,
    'match_lines': '\n'.join(match_lines),
    'nomatch_lines': '\n'.join(nomatch_lines),
    }
  print json.dumps(d, indent=2)


# Hook for snip
if __name__ == '__main__':
  import sys
  PrintJson(sys.argv[1])
